// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "DBManager/Repository/HDF5/Input/Property/PBRSECTRepository.h"

#include "DBManager/Repository/HDF5/Base/HDF5RepositoryMacro.h"

#include "PBRSECTRepository.h"

HDF5_REG_REPOSITORY (PBRSECTRepository)

using namespace SG::DBManager::HDF5;
using namespace SG::DBManager::HDF5::PBRSECT;
using namespace SG::DataStructure::FEM;
using namespace SG::DataStructure::Common;

PBRSECTRepository::PBRSECTRepository (HDF5Database& database) : SG::DBManager::HDF5::MainlyRepositoryBase<PBRSECTData> (database)
{}

void PBRSECTRepository::InitialDatasetInfo ()
{
    RegisterTableInfo<NasMainStruct> ("/SG/INPUT/PROPERTY/PBRSECT/IDENTITY", MainDataset);
    RegisterIndex ("/OWN/INDEX/INPUT/PROPERTY/PBRSECT", IndexDataset, GetType ());
    RegisterTableInfo<SubStructSECTION> ("/SG/INPUT/PROPERTY/PBRSECT/SECTION", SubDataset_Section);
    RegisterTableInfo<SubStructINP> ("/SG/INPUT/PROPERTY/PBRSECT/INP", SubDataset_Inp);
    RegisterTableInfo<SubStructING> ("/SG/INPUT/PROPERTY/PBRSECT/ING", SubDataset_Ing);

    // 连接信号槽 当调用汇总的时候，将已有的缓存信息全部都持久化到HDF5文件中。
    GetDatabase ().GetHDF5Hub ()->m_propertySummarySignal.connect ([this] { Sort (); });
}

void PBRSECTRepository::DumpWriteCahce ()
{
    auto& writeStorage = this->GetMainCache ().m_writeStorage;

    // 设置为无顺序
    GetMainDatasetInfo ().SetIsSequential (false);

    // 主表数据
    std::vector<IDENTITY> IDENTITYData{};
    // 附表数据
    std::vector<SubStructSECTION> SectionData;
    std::vector<SubStructINP>     inpData;
    std::vector<SubStructING>     ingData;

    // 转换为nastran格式数据
    OwnToNastran (writeStorage, IDENTITYData, SectionData, inpData, ingData);

    WriteData (MainDataset, IDENTITYData);
    WriteData (SubDataset_Section, SectionData);
    WriteData (SubDataset_Inp, inpData);
    WriteData (SubDataset_Ing, ingData);

    // 更新Index表
    this->WriteIndexData (this->GetIndexDatasetInfo (), writeStorage);

    // 清空缓存
    writeStorage.clear ();
}

std::vector<PBRSECTRepository::DataType>* PBRSECTRepository::LoadReadCache (std::size_t loadIndex)
{
    std::vector<IDENTITY> IDENTITYData;
    LoadMainMetadata (loadIndex, IDENTITYData);

    if (IDENTITYData.empty ())
    {
        return nullptr;
    }

    std::vector<SubStructSECTION> SectionData;
    std::vector<SubStructINP>     inpData;
    std::vector<SubStructING>     ingData;
    LoadSecondaryMetadata (IDENTITYData, SECTION_POS, SECTION_LEN, SubDataset_Section, SectionData);
    LoadSecondaryMetadata (SectionData, INP_POS, INP_LEN, SubDataset_Inp, inpData);
    LoadSecondaryMetadata (SectionData, ING_POS, ING_LEN, SubDataset_Ing, ingData);

    auto* cacheVector = m_cacheHelper.LookupOrCreateVector<DataType> (GetMainCache ().m_readCacheKey, IDENTITYData.size ());
    NastranToOwn (IDENTITYData, SectionData, inpData, ingData, *cacheVector);
    return cacheVector;
}

void PBRSECTRepository::SortData ()
{
    std::vector<IDENTITY> IDENTITYData;
    GetDataset (MainDataset).read (IDENTITYData);

    if (IDENTITYData.empty ())
    {
        GetMainDatasetInfo ().SetIsSequential (true);
        return;
    }

    std::vector<SubStructSECTION> SectionData;
    std::vector<SubStructINP>     inpData;
    std::vector<SubStructING>     ingData;
    GetDataset (SubDataset_Section).read (SectionData);
    GetDataset (SubDataset_Inp).read (inpData);
    GetDataset (SubDataset_Ing).read (ingData);

    // 将所有数据转换
    std::vector<SG::DataStructure::FEM::PBRSECTData> AllData{};
    NastranToOwn (IDENTITYData, SectionData, inpData, ingData, AllData);

    // 排序
    std::sort (AllData.begin (), AllData.end ());

    // 转换回nastran格式
    OwnToNastran (AllData, IDENTITYData, SectionData, inpData, ingData, true);

    // 写出数据至文件
    GetDataset (MainDataset).write (IDENTITYData);
    GetDataset (SubDataset_Section).write (SectionData);
    GetDataset (SubDataset_Inp).write (inpData);
    GetDataset (SubDataset_Ing).write (ingData);

    // 重写索引
    RewriteIndexData (AllData);

    // 设置为已顺序
    GetMainDatasetInfo ().SetIsSequential (true);
}
std::vector<SG::DataStructure::FEM::PBRSECTData> PBRSECTRepository::GetAllData ()
{
    Sort ();

    std::vector<MainStruct> result;

    std::vector<SG::DBManager::HDF5::PBRSECT::IDENTITY> IDENTITYData;
    GetDataset (MainDataset).read (IDENTITYData);

    if (IDENTITYData.empty ())
    {
        return result;
    }

    std::vector<SubStructSECTION> SectionData;
    std::vector<SubStructINP>     inpData;
    std::vector<SubStructING>     ingData;
    GetDataset (SubDataset_Section).read (SectionData);
    GetDataset (SubDataset_Inp).read (inpData);
    GetDataset (SubDataset_Ing).read (ingData);

    // 将所有数据转换
    NastranToOwn (IDENTITYData, SectionData, inpData, ingData, result);

    return result;
}

void PBRSECTRepository::OwnToNastran (std::vector<SG::DataStructure::FEM::PBRSECTData>&         own,
                                      std::vector<SG::DBManager::HDF5::PBRSECT::IDENTITY>& _OUT IDENTITYData,
                                      std::vector<SubStructSECTION>& _OUT                       SectionData,
                                      std::vector<SubStructINP>& _OUT                           inpData,
                                      std::vector<SubStructING>& _OUT                           ingData,
                                      bool                                                      isSort)
{
    SectionData.clear ();
    inpData.clear ();
    ingData.clear ();
    IDENTITYData.clear ();
    IDENTITYData.reserve (own.size ());

    // 获取已有数据条数，主要是放在主表的POS字段
    // 如果是重新排序的时候，Pos都是从0 开始的
    size_t SectionCount = isSort ? 0 : this->GetDatasetInfo (SubDataset_Section).GetRowCount ();
    size_t inpCount     = isSort ? 0 : this->GetDatasetInfo (SubDataset_Inp).GetRowCount ();
    size_t ingCount     = isSort ? 0 : this->GetDatasetInfo (SubDataset_Ing).GetRowCount ();

    // OwnIdent 代表咱们自己的数据结构
    // NasIdent 代表nastran的数据结构
    for (auto& OwnIdent : own)
    {
        // 写入附表
        // SectionData.insert (SectionData.end (), OwnIdent.section.begin (), OwnIdent.section.end ());
        const size_t len = OwnIdent.m_sections.size ();

        for (size_t i = 0; i < len; i++)
        {
            inpData.insert (inpData.end (), OwnIdent.m_sections[i].inps.begin (), OwnIdent.m_sections[i].inps.end ());
            ingData.insert (ingData.end (), OwnIdent.m_sections[i].ings.begin (), OwnIdent.m_sections[i].ings.end ());

            SubStructSECTION ss;
            ss.OHEIGHT = OwnIdent.m_sections[i].OHEIGHT;
            ss.OWIDTH  = OwnIdent.m_sections[i].OWIDTH;
            ss.INP_POS = inpCount;
            ss.ING_POS = inpCount;
            ss.INP_LEN = OwnIdent.m_sections[i].inps.size ();
            ss.ING_LEN = OwnIdent.m_sections[i].ings.size ();
            SectionData.push_back (ss);

            inpCount += OwnIdent.m_sections[i].inps.size ();
            ingCount += OwnIdent.m_sections[i].ings.size ();
        }

        // 写入IDENTITY
        IDENTITY NasIdent{};
        NasIdent.SID         = OwnIdent.m_id;
        NasIdent.MID         = OwnIdent.m_MID;
        NasIdent.FORM        = OwnIdent.m_FORM;
        NasIdent.RECLEN      = OwnIdent.m_RECLEN;
        NasIdent.NSM         = OwnIdent.m_NSM;
        NasIdent.OUTP        = OwnIdent.m_OUTP;
        NasIdent.OUTG        = OwnIdent.m_OUTG;
        NasIdent.OUTM        = OwnIdent.m_OUTM;
        NasIdent.SECTION_POS = SectionCount;
        NasIdent.SECTION_LEN = len;
        NasIdent.DOMAIN_ID   = OwnIdent.m_domainId;

        IDENTITYData.emplace_back (NasIdent);

        SectionCount += len;
    }
}

void PBRSECTRepository::NastranToOwn (std::vector<SG::DBManager::HDF5::PBRSECT::IDENTITY>& IDENTITYData,
                                      std::vector<SubStructSECTION>&                       sectionData,
                                      std::vector<SubStructINP>&                           inpData,
                                      std::vector<SubStructING>&                           ingData,
                                      std::vector<MainStruct>& _OUT                        own)
{
    own.clear ();
    own.reserve (IDENTITYData.size ());

    // 代表初始的Index 位置, 因为数据有可能是截取了附表的一部分，所有主表中根据POS找的时候需要对应一下，
    // 比如第一个主表数据中POS字段为10000， 附表的vector的数据 就是从附表中的第10000个开始对应的 也就是Index==0的
    const SG::DataStructure::Common::I64 index    = IDENTITYData[0].SECTION_POS;
    SG::DataStructure::Common::I64       inpIndex = sectionData.size () > 0 ? sectionData[0].INP_POS : 0;
    SG::DataStructure::Common::I64       ingIndex = sectionData.size () > 0 ? sectionData[0].ING_POS : 0;

    PBRSECTData tempown;
    own.resize (IDENTITYData.size (), tempown);

    for (size_t i = 0; i < IDENTITYData.size (); i++)
    {
        auto& OwnIdent = own[i];
        auto& NasIdent = IDENTITYData[i];

        OwnIdent.m_id       = NasIdent.SID;
        OwnIdent.m_MID      = NasIdent.MID;
        OwnIdent.m_FORM     = NasIdent.FORM;
        OwnIdent.m_RECLEN   = NasIdent.RECLEN;
        OwnIdent.m_NSM      = NasIdent.NSM;
        OwnIdent.m_OUTP     = NasIdent.OUTP;
        OwnIdent.m_OUTG     = NasIdent.OUTG;
        OwnIdent.m_OUTM     = NasIdent.OUTM;
        OwnIdent.m_domainId = NasIdent.DOMAIN_ID;

        if (NasIdent.SECTION_LEN != 0)
        {
            OwnIdent.m_sections.resize (NasIdent.SECTION_LEN);
            // OwnIdent.m_sections.assign (sectionData.begin () + NasIdent.GIDS_POS - index,
            //                         sectionData.begin () + NasIdent.GIDS_POS + NasIdent.GIDS_LEN - index);
            for (SG::DataStructure::Common::I64 j = 0; j < NasIdent.SECTION_LEN; j++)
            {
                SubStructSECTION     ss = sectionData[j + NasIdent.SECTION_POS - index];
                MainStruct::section& ms = OwnIdent.m_sections[j];
                ms.OWIDTH               = ss.OWIDTH;
                ms.OHEIGHT              = ss.OHEIGHT;
                ms.inps.assign (inpData.begin () + ss.INP_POS - inpIndex, inpData.begin () + ss.INP_POS + ss.INP_LEN - inpIndex);
                ms.ings.assign (ingData.begin () + ss.ING_POS - ingIndex, ingData.begin () + ss.ING_POS + ss.ING_LEN - ingIndex);
            }
        }
    }
}
